package open.witype.filetiper.custom.Slidingmenu;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.NonNull;
import android.support.v4.view.VelocityTrackerCompat;
import android.support.v4.view.ViewConfigurationCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import android.view.animation.Interpolator;
import android.widget.Scroller;

import open.witype.filetiper.R;

/**
 * Created by Typer on 2015/5/9 0009.
 * 承载内容的布局
 */
public class AboveViewContent extends SlidingContentBase {

    private Scroller mScroller;

    public float mLastX;

    public float mLastY;

    public float mDownX;

    private SlidingMenuView.onSlidingStatusChanged menuListener;

    public BehindViewContent behindContent;

    /**
     * 滑动的速度
     */
    public VelocityTracker mVelocityTracker;

    /**
     * 系统定义最小滑动速度
     */
    public int minVelocity;

    /**
     * 系统定义最大滑动速度
     */
    public int maxVelocity;

    /**
     * 滑动的距离
     */
    public float mFlingDistance;

    /**
     * 当前是否已经处于滑动状态
     */
    public boolean isDraging;

    public boolean mIsUnableToDrag;

    /**
     * 系统定义了最小的滑动距离
     */
    public int mDefaultSlop;

    /**
     *
     */
    public int mScrollX;

    public int mCurItem;


    public static final Interpolator mInterpolator = new Interpolator() {
        @Override
        public float getInterpolation(float input) {
            input -= 1.0f;
            return input * input * input * input * input * input * input + 1.0f;
        }
    };

    public AboveViewContent(Context context) {
        this(context, null);
    }

    public AboveViewContent(Context context, AttributeSet attrs) {
        super(context, attrs);
        ViewConfiguration configuration = ViewConfiguration.get(context);
        minVelocity = configuration.getScaledMinimumFlingVelocity();
        maxVelocity = configuration.getScaledMaximumFlingVelocity();
        mDefaultSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
        mScroller = new Scroller(context, mInterpolator);
        float density = context.getResources().getDisplayMetrics().density;
        mFlingDistance = (int) (MIN_FLING_DISTATNCE * density);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = getDefaultSize(0, widthMeasureSpec);
        int height = getDefaultSize(0, heightMeasureSpec);
        setMeasuredDimension(width, height);
        int contentWidth = getChildMeasureSpec(widthMeasureSpec, 0, width);
        int contentHeight = getChildMeasureSpec(heightMeasureSpec, 0, height);
        mContent.measure(contentWidth, contentHeight);
    }

    @Override
    protected void dispatchDraw(@NonNull Canvas canvas) {
        super.dispatchDraw(canvas);
        Paint paint = new Paint();
        paint.setColor(getContext().getResources().getColor(R.color.divider));
        int left = getLeft() - 1;
        int top = 0;
        int right = getLeft();
        int bottom = getHeight();
        canvas.drawLine(left, top, right, bottom, paint);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        int action = event.getAction();
        switch (action){
            case MotionEvent.ACTION_DOWN:
                float x = event.getRawX();
                mLastX = mDownX = x;
                mLastY = event.getRawY();
                if(isTouchAllowed(event)){
                    isDraging = false;
                    mIsUnableToDrag = false;
                }else{
                    mIsUnableToDrag = true;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                checkIsDraged(event);
                break;
            case MotionEvent.ACTION_UP:

                break;
        }
        return isDraging;
    }

    @Override
    public boolean onTouchEvent(@NonNull MotionEvent event) {
        if (!isDraging && !isTouchAllowed(event)) {
            return false;
        }
        if (mVelocityTracker == null)
            mVelocityTracker = VelocityTracker.obtain();
        mVelocityTracker.addMovement(event);
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mLastX = mDownX = event.getX();
                break;
            case MotionEvent.ACTION_MOVE:
                /**
                 * 如果之前的状态是没有在滑动
                 * 现在开始滑动,对滑动开始检测
                 */
                if (!isDraging) {
                    checkIsDraged(event);
                }
                if (isDraging) {
                    float xMove = event.getX();
                    /**
                     * 计算移动距离
                     * 向左移动正数
                     * 向右移动为负数
                     */
                    float xDistance = mLastX - xMove;

                    mLastX = xMove;//为xLast重新给定位置
                    int oldScrollX = getScrollX();//oldScrollX 为负数
                    float scrollX = oldScrollX + xDistance;
                    int leftBound = behindContent.getLeftRelativeBound();
                    int rightBound = behindContent.getRightRelativeBound();
                    if (scrollX < leftBound)
                        scrollX = leftBound;
                    else if (scrollX > rightBound)
                        scrollX = rightBound;
                    scrollTo((int) scrollX, 0);
                }
                break;
            case MotionEvent.ACTION_UP:
                if (isDraging) {
                    VelocityTracker velocityTracker = mVelocityTracker;
                    velocityTracker.computeCurrentVelocity(1000, maxVelocity);
                    float xUp = event.getX();
                    int velocity = (int) VelocityTrackerCompat.getXVelocity(mVelocityTracker, 0);
                    int flingDistance = (int) (xUp - mDownX);
                    mCurItem = checkPage(flingDistance, velocity);
                    setCurPage(mCurItem);
                    stopDragged();
                }
                break;
        }
        return true;
    }

    public void checkIsDraged(MotionEvent event) {
        //x方向移动距离
        float x = event.getX();
        float dx = Math.abs(mLastX - x);
        if (dx > mDefaultSlop && isTouchAllowed(event)) {
            beginDragged();
            mLastX = event.getX();
        } else if (dx > mDefaultSlop) {
            mIsUnableToDrag = true;
        }
    }

    public int checkPage(int distance, int velocity) {
        int targetPage = mCurItem;
        if (Math.abs(distance) > mFlingDistance && Math.abs(velocity) > minVelocity) {
            if ((distance > 0 && velocity > 0) || distance > mFlingDistance) {
                targetPage += 1;
            } else if ((distance < 0 && velocity < 0 || distance < -mFlingDistance)) {
                targetPage -= 1;
            }
        }
        if (Math.abs(distance) > behindContent.getWidthOffset() / 2 || Math.abs(velocity) > maxVelocity) {
            if (distance > -behindContent.getSecondaryLeftRelativeBound()) {
                targetPage = 2;
            } else if (distance < 0) {
                targetPage = 0;
            }
        }
        targetPage = targetPage > 2 ? 2 : targetPage;
        targetPage = targetPage < 0 ? 0 : targetPage;
        return targetPage;
    }

    public void setCurPage(int page) {
        page = getCurPageDimen(page);
        if (menuListener != null)
            switch (mCurItem) {
                case 0:
                    menuListener.onSlidingClose(mCurItem);
                    break;
                default:menuListener.onSlidingOpen(mCurItem);
            }
        int sx = getScrollX();
        int dx = page - sx;
        mScroller.startScroll(sx, 0, dx, 0, 600);
        postInvalidate();
    }

    public int getCurPageDimen(int page) {
        int dest;
        switch (page) {
            //main face
            case 0:
                dest = behindContent.getRightRelativeBound();
                break;
            //secondary face
            case 1:
                dest = behindContent.getSecondaryLeftRelativeBound();
                break;
            //all menuu face
            case 2:
                dest = behindContent.getLeftRelativeBound();
                break;
            default:
                dest = 0;
                break;
        }
        return dest;
    }

    /**
     * 点击的区域是否可以被滑动
     * 1.如果菜单打开,则菜单区域是不能被滑动的
     *
     * @param event 传入事件
     * @return 点击的区域是否可以支持滑动
     */
    public boolean isTouchAllowed(MotionEvent event) {
        float x = event.getX();
        //菜单打开
        if (isMenuOpen()) {
            return  x > -getCurPageDimen(mCurItem);
        }
        return true;
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            int oldX = getScrollX();
            int x = mScroller.getCurrX();
            int y = mScroller.getCurrY();
            if (oldX != x) {
                scrollTo(x, y);
            }
            invalidate();
        }
    }

    public void openMenu(int page) {
        setCurPage(page);
    }

    public void closeMenu() {
        setCurPage(2);
    }

    public void beginDragged() {
        isDraging = true;
    }

    public void setMenuListener(SlidingMenuView.onSlidingStatusChanged listener) {
        this.menuListener = listener;
    }

    public void stopDragged() {
        isDraging = false;
        mIsUnableToDrag = false;
        if (mVelocityTracker != null) {
            mVelocityTracker.recycle();
            mVelocityTracker = null;
        }
    }

    public boolean isMenuOpen() {
        return mCurItem == 1 || mCurItem == 2;
    }

    @Override
    public void scrollTo(int x, int y) {
        super.scrollTo(x, y);
        mScrollX = x;
    }

    public void setBehindContent(BehindViewContent behindContent) {
        this.behindContent = behindContent;
    }
}
